module MidLevelTranslators where

import MidLevelLanguageTokenizer (Token(Variable, CharacterVariable,
                                         Conditional, Loop, EndBlock, Operation), 
                                OpType, CondType, Comparator)

-- | Translates a tokenized program into simple, pure C.
midLevelToC :: [Token] -> String
midLevelToC x = "int main() {\n" ++ unlines (midLevelToCStrings x) ++ "}\n"

-- | Translates a tokenized program into simple, pure C instructions.
midLevelToCStrings :: [Token] -> [String]
midLevelToCStrings x = map (midLevelToCInstruction) x

-- | Translates a Token into a C instruction.
midLevelToCInstruction :: Token -> String
midLevelToCInstruction (Variable n v)   -- Any integer variable
                = "int " ++ n ++ " = " ++ show v ++ ";"

midLevelToCInstruction (CharacterVariable n v)  
        | v == '\0'     -- Uninitialized character variable
                = "char " ++ n ++ ";"   
        | otherwise      -- Initialized character variable
                = "char " ++ n ++ " = " ++ show v ++ ";" 

midLevelToCInstruction (Loop var ini end) 
        | var == "" = "for (;;){"       -- Infinite "for" loop
        | otherwise                     -- Other "for" loops 
                = "for (" ++ var ++ " = " ++ show ini ++ "; " ++ var 
                ++ " == " ++ show end ++ ";){"

midLevelToCInstruction (EndBlock) = "}"

midLevelToCInstruction (Operation op var i)
        -- Basic arithmetic operations
        | i == 1 && op == ((read "Increment")::OpType)  -- x++;
                = var ++ "++;"
        | i == 1 && op == ((read "Decrement")::OpType)  -- x--;
                = var ++ "--;"
        | op == ((read "Increment")::OpType)            -- x = x + #value;
                = var ++ " = " ++ var ++ "+" ++ show i ++ ";"
        | op == ((read "Decrement")::OpType)            -- x = x - #value;
                = var ++ " = " ++ var ++ "+" ++ show i ++ ";"
        | op == ((read "Read")::OpType)                 -- x = getchar();
                = var ++ " = getchar();"
        | op == ((read "Write")::OpType)                -- putchar(#variable);
                = "putchar(" ++ var ++ ");"
        | otherwise = ""

midLevelToCInstruction (Conditional ct var cmp end)
        -- If conditionals
        | ifComp && eqt
                = "if (" ++ var ++ " == " ++ show end ++ ") {"
        | ifComp && neq
                = "if (" ++ var ++ " != " ++ show end ++ ") {"
        | ifComp && bgt
                = "if (" ++ var ++ " > " ++ show end ++ ") {"
        | ifComp && bge
                = "if (" ++ var ++ " >= " ++ show end ++ ") {"
        | ifComp && lst
                = "if (" ++ var ++ " < " ++ show end ++ ") {"
        | ifComp && lse
                = "if (" ++ var ++ " <= " ++ show end ++ ") {"
        --TODO: While
        | otherwise = ""
        where   ifComp = ct == ((read "If") :: CondType)        -- if (...
                eqt = cmp == ((read "Equal") :: Comparator)     -- x == #value
                neq = cmp == ((read "NotEqual") :: Comparator)  -- x != #value
                bgt = cmp == ((read "Bigger") :: Comparator)    -- x > #value
                bge = cmp == ((read "BiggerEq") :: Comparator)  -- x >= #value
                lst = cmp == ((read "Lesser") :: Comparator)    -- x < #value
                lse = cmp == ((read "LesserEq") :: Comparator)  -- x <= #value
